﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace liuzw.utils
{
    internal static class DictionaryExtensions
    {
         /// <summary>
         /// 不存在则新增，存在则更新
         /// </summary>
         /// <typeparam name="TKey"></typeparam>
         /// <typeparam name="TValue"></typeparam>
         /// <param name="dic"></param>
         /// <param name="key"></param>
         /// <param name="value"></param>
         /// <returns></returns>
        public static Dictionary<TKey, TValue> AddOrUpdate<TKey, TValue>
        (this Dictionary<TKey, TValue> dic, TKey key, TValue value)
        {
            lock (dic)
            {
                if (dic.ContainsKey(key))
                    dic[key] = value;
                else
                    dic.Add(key, value);
                return dic;
            }
        }
        /// <summary>
        /// 存在，则不写入。不存在才写入
        /// </summary>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TValue"></typeparam>
        /// <param name="dic"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static Dictionary<TKey, TValue> TryAdd<TKey, TValue>
        (this Dictionary<TKey, TValue> dic, TKey key, TValue value)
        {
            if (!dic.ContainsKey(key))
                dic.Add(key, value);
            return dic;
        }

        public static Dictionary<string, List<T>> AddOrUpdateList<T>(this Dictionary<string, List<T>> dic, T data, string key)
        {
            lock (dic)
            {
                if (dic != null)
                {
                    if (dic.ContainsKey(key))
                    {
                        dic[key].Add(data);
                    }
                    else
                    {
                        dic.Add(key, new List<T> { data });
                    }
                }
                return dic;
            }
        }


        /// <summary>
        /// 忽略某些属性
        /// </summary>
        /// <param name="source"></param>
        /// <param name="ignoredProperties"></param>
        /// <returns></returns>
        public static Dictionary<string, object> ToDictionary(this object source, string[] ignoredProperties)
        {
            var dictionary = source.ToDictionary<object>();
            foreach (var property in ignoredProperties)
            {
                dictionary.Remove(property);
            }
            return dictionary;
        }
        public static Dictionary<string, object> ToDictionary(this object source)
        {
            return source.ToDictionary<object>();
        }
        public static Dictionary<string, T> ToDictionary<T>(this object source)
        {
            if (source == null)
                ThrowExceptionWhenSourceArgumentIsNull();
            var dictionary = new Dictionary<string, T>();
            foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source))
            {
                AddPropertyToDictionary<T>(property, source, dictionary);
            }
            return dictionary;
        }
        private static void AddPropertyToDictionary<T>(PropertyDescriptor property, object source, Dictionary<string, T> dictionary)
        {
            if (IsIgnore(property))
                return;
            var value = property.GetValue(source);
            if (IsOfType<T>(value))
            {
                var propertyName = GetPropertyName(property);
                dictionary.Add(string.IsNullOrEmpty(propertyName) ? property.Name : propertyName, (T)value);
            }
        }
        private static bool IsIgnore(PropertyDescriptor property)
        {
            if (property.Attributes.OfType<DictionaryIgnore>().Any())
            {
                return true;
            }
            return false;
        }
        private static string GetPropertyName(PropertyDescriptor property)
        {
            var jsonProperty = property.Attributes.OfType<JsonPropertyAttribute>();
            if (jsonProperty.Any())
            {
                return jsonProperty.FirstOrDefault()?.PropertyName;
            }
            return null;
        }
        private static bool IsOfType<T>(object value)
        {
            return value is T;
        }
        private static void ThrowExceptionWhenSourceArgumentIsNull()
        {
            throw new ArgumentNullException("source", "Unable to convert object to a dictionary. The source object is null.");
        }
    }
    public class DictionaryIgnore : System.Attribute
    {
    }
}
